/*
* WavReader.cpp
*
*  Created on: Mar 21, 2013
*      Author: Scorpion
*/

#include "WavReader.h"
#include <assert.h>
namespace centny {
	namespace abl {

		WavReader::WavReader(const char* fpath) {
			assert(sizeof(int)==4&&sizeof(short)==2);
			this->fhandle=fopen(fpath,"rb");
			assert(this->fhandle);
			fread(ChunkID,1,4,fhandle);
			fread(&ChunkSize,4,1,fhandle);
			fread(Format,1,4,fhandle);
			fread(Subchunk1ID,1,4,fhandle);
			fread(&Subchunk1Size,4,1,fhandle);
			fread(&AudioFormat,2,1,fhandle);
			fread(&NumChannels,2,1,fhandle);
			fread(&SampleRate,4,1,fhandle);
			fread(&ByteRate,4,1,fhandle);
			fread(&BlockAlign,2,1,fhandle);
			fread(&BitsPerSample,2,1,fhandle);
			fread(&Subchunk2ID,1,4,fhandle);
			fread(&Subchunk2Size,4,1,fhandle);
		}
		int WavReader::rate(){
			return this->SampleRate;
		}
		int WavReader::bytesPerSample(){
			return this->BitsPerSample/8;
		}
		AudioBlock* WavReader::readSingle(bool derivative,int len){
			int bps=this->bytesPerSample();
			assert(bps>0);
			AudioBlock* ab=0;
			switch (bps)
			{
			case 1:
				{
					if(len<1){
						len=this->Subchunk2Size;
					}
					char* data=new char[len];
					fread(data,bps,len,this->fhandle);
					ab=create(this->rate(),bps,data,len,derivative);
					delete data;
				}
				break;
			case 2:
				{
					if(len<1){
						len=this->Subchunk2Size/bps;
					}
					int* data=new int[len];
					int val=0;
					for(int i=0;i<len;i++){
						fread(&val,bps,1,this->fhandle);
						data[i]=(short)val;
					}
					ab=create(this->rate(),bps,data,len,derivative);
					delete data;
				}
				break;
			case 3:
				assert(false);
				break;
			case 4:
				{
					if(len<1){
						len=this->Subchunk2Size/bps;
					}
					int* data=new int[len];
					fread(&data,bps,len,this->fhandle);
					ab=create(this->rate(),bps,data,len,derivative);
					delete data;
				}
				break;
			default:
				assert(false);
				break;
			}
			return ab;
		}
		std::pair<AudioBlock*,AudioBlock*> WavReader::readTwo(bool derivative,int len){
			std::pair<AudioBlock*,AudioBlock*> abs(0,0);
			int bps=this->bytesPerSample();
			assert(bps>0);
			AudioBlock	*left=0,*right=0;
			switch (bps)
			{
			case 1:
				{
					if(len<1){
						len=this->Subchunk2Size/2;
					}
					char* ldata=new char[len];
					char* rdata=new char[len];
					char val;
					for(int i=0;i<len;i++){
						fread(&val,1,1,this->fhandle);
						ldata[i]=val;
						fread(&val,1,1,this->fhandle);
						rdata[i]=val;
					}
					left=create(this->rate(),bps,ldata,len,derivative);
					right=create(this->rate(),bps,rdata,len,derivative);
					delete ldata;
					delete rdata;
				}
				break;
			case 2:
				{
					if(len<1){
						len=this->Subchunk2Size/2;
					}
					int* ldata=new int[len];
					int* rdata=new int[len];
					int val;
					for(int i=0;i<len;i++){
						fread(&val,bps,1,this->fhandle);
						ldata[i]=(short)val;
						fread(&val,bps,1,this->fhandle);
						rdata[i]=(short)val;
					}
					left=create(this->rate(),bps,ldata,len,derivative);
					right=create(this->rate(),bps,rdata,len,derivative);
					delete ldata;
					delete rdata;
				}
				break;
			case 3:
				assert(false);
				break;
			case 4:
				{
					if(len<1){
						len=this->Subchunk2Size/2;
					}
					int* ldata=new int[len];
					int* rdata=new int[len];
					int val;
					for(int i=0;i<len;i++){
						fread(&val,bps,1,this->fhandle);
						ldata[i]=val;
						fread(&val,bps,1,this->fhandle);
						rdata[i]=val;
					}
					left=create(this->rate(),bps,ldata,len,derivative);
					right=create(this->rate(),bps,rdata,len,derivative);
					delete ldata;
					delete rdata;
				}
				break;
			default:
				assert(false);
				break;
			}
			abs.first=left;
			abs.second=right;
			return abs;
		}
		std::pair<AudioBlock*,AudioBlock*> WavReader::read(bool derivative,int len){
			switch (this->NumChannels)
			{
			case 1:
				{
					std::pair<AudioBlock*,AudioBlock*> abs(0,0);
					abs.first=this->readSingle(derivative,len);
					return abs;
				}
				break;
			case 2:
				{
					return this->readTwo(derivative,len);
				}
				break;
			default:
				assert(false);
				break;
			}
			return std::pair<AudioBlock*,AudioBlock*>(0,0);
		}
		WavReader::~WavReader() {
			if(this->fhandle){
				fclose(this->fhandle);
				this->fhandle=0;
			}
		}

	} /* namespace abl */
} /* namespace centny */
